import tkinter.ttk as ttk
from operator import index

import serial.tools.list_ports

from links.abstract_link import AbstractLink
from links.abstract_link_ui import AbstractUiLink
from links.serial_port_link import SerialPortLink, SerialPortLinkDataKeys


class SerialPortLinkUi(AbstractUiLink):
    def __init__(self, parent):
        super().__init__(parent)
        self.port_name_cb = ttk.Combobox(self)
        self.baud_rate_cb = ttk.Combobox(self)
        self.data_bits_cb = ttk.Combobox(self)
        self.stop_bits_cb = ttk.Combobox(self)
        self.parity_cb = ttk.Combobox(self)
        self.flow_control_cb = ttk.Combobox(self)
        self.create_widgets()

    def create_widgets(self):
        row = 0
        port_name_label = ttk.Label(self, text="Port Name:")
        port_name_label.grid(row=row, column=0, sticky="nsew", padx=2, pady=2)
        self.port_name_cb.grid(row=row, column=1, sticky="nsew", padx=2, pady=2)
        ports = list(serial.tools.list_ports.comports())
        port_names = [port.device for port in ports]
        self.port_name_cb["values"] = port_names
        self.port_name_cb.current(0)
        self.port_name_cb.config(state="readonly")
        row += 1

        baud_rate_label = ttk.Label(self, text="Baud Rate:")
        baud_rate_label.grid(row=row, column=0, sticky="nsew", padx=2, pady=2)
        # fmt: off
        bds = [
            9600, 19200, 38400, 57600, 115200, 230400, 460800, 500000, 576000, 921600,
            1000000, 1152000, 1500000, 2000000, 2500000, 3000000, 3500000, 4000000
        ]
        # fmt: on
        baud_rate_cb = ttk.Combobox(self, values=bds)
        baud_rate_cb.grid(row=row, column=1, sticky="nsew", padx=2, pady=2)
        baud_rate_cb.current(0)
        self.baud_rate_cb = baud_rate_cb
        row += 1

        data_bits_label = ttk.Label(self, text="Data Bits:")
        data_bits_label.grid(row=row, column=0, sticky="nsew", padx=2, pady=2)
        data_bits_cb = ttk.Combobox(self, values=["8", "7", "6", "5"])
        data_bits_cb.grid(row=row, column=1, sticky="nsew", padx=2, pady=2)
        data_bits_cb.current(0)
        data_bits_cb.config(state="readonly")
        self.data_bits_cb = data_bits_cb
        row += 1

        stop_bits_label = ttk.Label(self, text="Stop Bits:")
        stop_bits_label.grid(row=row, column=0, sticky="nsew", padx=2, pady=2)
        stop_bits_cb = ttk.Combobox(self, values=["1", "1.5", "2"])
        stop_bits_cb.grid(row=row, column=1, sticky="nsew", padx=2, pady=2)
        stop_bits_cb.current(0)
        stop_bits_cb.config(state="readonly")
        self.stop_bits_cb = stop_bits_cb
        row += 1

        parity_label = ttk.Label(self, text="Parity bits:")
        parity_label.grid(row=row, column=0, sticky="nsew", padx=2, pady=2)
        parity_cb = ttk.Combobox(self, values=["None", "Even", "Odd", "Mark", "Space"])
        parity_cb.grid(row=row, column=1, sticky="nsew", padx=2, pady=2)
        parity_cb.current(0)
        parity_cb.config(state="readonly")
        self.parity_cb = parity_cb
        row += 1

        flow_control_label = ttk.Label(self, text="Flow Control:")
        flow_control_label.grid(row=row, column=0, sticky="nsew", padx=2, pady=2)
        flow_control_cb = ttk.Combobox(
            self, values=["None", "RTS/CTS(H)", "XON/XOFF(S)"]
        )
        flow_control_cb.grid(row=row, column=1, sticky="nsew", padx=2, pady=2)
        flow_control_cb.current(0)
        flow_control_cb.config(state="readonly")
        self.flow_control_cb = flow_control_cb
        row += 1

        self.grid_columnconfigure(1, weight=1)

    def create_io(self) -> AbstractLink:
        io = SerialPortLink()
        return io

    def save(self) -> dict:
        ctx = {}
        keys = SerialPortLinkDataKeys()
        ctx[keys.PORT_NAME] = self.port_name_cb.get()
        ctx[keys.BAUD_RATE] = self.baud_rate_cb.get()
        ctx[keys.DATA_BITS] = self.data_bits_cb.get()
        ctx[keys.STOP_BITS] = self.stop_bits_cb.get()
        ctx[keys.PARITY] = self.parity_cb.get()
        ctx[keys.FLOW_CONTROL] = self.flow_control_cb.get()
        return ctx

    def load(self, parameters: dict):
        ctx = {}
        keys = SerialPortLinkDataKeys()
        port_name = parameters.get(keys.PORT_NAME)
        baud_rate = parameters.get(keys.BAUD_RATE)
        data_bits = parameters.get(keys.DATA_BITS)
        stop_bits = parameters.get(keys.STOP_BITS)
        parity = parameters.get(keys.PARITY)
        flow_control = parameters.get(keys.FLOW_CONTROL)
        self.port_name_cb.set(port_name)
        self.baud_rate_cb.set(baud_rate)
        self.data_bits_cb.set(data_bits)
        self.stop_bits_cb.set(stop_bits)
        self.parity_cb.set(parity)
        self.flow_control_cb.set(flow_control)
        return ctx
